import numpy as np
from sko.GA import GA_TSP
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.patches import Patch
import datetime
import time

# 计算规划的订单信息,第一个输入为规划的订单顺序，第二个为订单信息，第三个为转生产消耗信息
def cal_order_sequence(order_sequence_list, order_info, transform_cost):
    # 将原始订单列表按照现在生成的订单顺序排好
    order_sequence_list_info = []
    for i in range(0, len(order_sequence_list)):
        # 读取当前列表中第i个，在原始订单列表中排第几
        select_order_index = order_sequence_list[i]
        temp_order = order_info[select_order_index]
        order_sequence_list_info.append(temp_order)
    # print(order_sequence_list_reorder)

    # 时间轴顺序列表(开始时间)
    time_start_list = []
    # 时间轴顺序列表(结束时间)
    time_end_list = []
    # 消耗时间顺序列表
    transform_cost_list = []
    for index, value in enumerate(order_sequence_list_info):
        # 起始时间
        start_time = 0
        # 结束时间
        end_time = 0
        # 转产消耗时间
        transform_cost_temp = 100000
        if index != 0:
            # 计算时间轴顺序(结束时间)
            transform_cost_time_string = order_sequence_list_info[index - 1][0] + '-' + value[0]
            transform_cost_temp = 100000
            for i, v in enumerate(transform_cost):
                if (v['name'] == transform_cost_time_string):
                    transform_cost_temp = v['cost']
                    break
                else:
                    transform_cost_temp = 100000
            end_time = time_end_list[index - 1] + value[2] + transform_cost_temp

            # 计算时间轴顺序(起始时间)
            start_time = time_end_list[index - 1] + transform_cost_temp
        else:
            # 第一单数据起始时间为0,结束时间为制造时间,转产消耗为0
            start_time = 0
            transform_cost_temp = 0
            end_time = value[2]
        time_end_list.append(end_time)
        time_start_list.append(start_time)
        transform_cost_list.append(transform_cost_temp)

    # 时间轴顺序信息
    product_time_axis_info_list = []
    for index, value in enumerate(order_sequence_list_info):
        temp = value.copy()
        temp.append(time_start_list[index])
        temp.append(time_end_list[index])
        temp.append(transform_cost_list[index])
        product_time_axis_info_list.append(temp)
    # 返回列表里前四列是原始信息：1.类型，2.订单号，3.制造所需时间，4.交付时间，
    # 此后三列为：5.制造开始时间（开始时间为0）6.制造完成的时间轴（开始时间为0），
    # 7.与前一个流程衔接所消耗时间
    return product_time_axis_info_list

# 计算适应度，求整体最小值
def cal_fitness(order_sequence_np):
    order_sequence_list = np.concatenate([order_sequence_np])
    # 获取整个时间轴
    product_time_axis_info_list = cal_order_sequence(order_sequence_list, order_info, transform_cost)
    # 计算衔接环节所消耗时间的适应度
    # 衔接环节所消耗时间的适应度
    transform_cost_value = 0
    for index, value in enumerate(product_time_axis_info_list):
        transform_cost_value = transform_cost_value + value[6]
    # 计算超时的适应度
    # 超时的适应度，如果有一个小于0，即没准时，则惩罚100分
    over_time_value = 100
    for index, value in enumerate(product_time_axis_info_list):
        # 计算超时的适应度,value[3]即第四列是交付时间;value[5]即第六列是结束时间
        temp_value = value[3] - value[5]
        if (temp_value < 0):
            over_time_value = 100
            break
        else:
            over_time_value = 0
    # 最后返回相加所得，整体是求最小值
    total_value = transform_cost_value + over_time_value

    # 显示甘特图
    # order_sequence_df = pd.DataFrame(product_time_axis_info_list)
    # order_sequence_df.columns = ['machine_type', 'order_no', 'product_time', 'due_date',
    #                              'start_time', 'end_time', 'tranform_cost']
    # # 颜色信息
    # legend_elements = [Patch(facecolor=c_dict[i], label=i) for i in c_dict]
    # # 排序
    # order_sequence_df['color'] = order_sequence_df.apply(getMachineTypeColor, axis=1)
    # sort_order_sequence_df = order_sequence_df.sort_values(by=['order_no'], ascending=[True])
    # # 作图
    # fig, ax = plt.subplots(1, figsize=(10, 4))
    # ax.barh(sort_order_sequence_df.order_no, sort_order_sequence_df.product_time,
    #         left=sort_order_sequence_df.start_time, color=sort_order_sequence_df.color)
    # ax.barh(sort_order_sequence_df.order_no, sort_order_sequence_df.tranform_cost,
    #         left=sort_order_sequence_df.start_time - sort_order_sequence_df.tranform_cost,
    #         color='#34D05C', alpha=0.5)
    # ax.barh(sort_order_sequence_df.order_no, 0.2,
    #         left=sort_order_sequence_df.due_date,
    #         color='#E64646')
    # plt.legend(handles=legend_elements)
    # plt.savefig('../img/pic-{}.png'.format(time.strftime('%Y_%m_%d_%H_%M_%S', time.localtime(time.time()))))
    # plt.show(block=False)
    # plt.pause(1)
    # plt.close()

    # 返回值
    return total_value

# 画甘特图时，获取机型颜色
def getMachineTypeColor(row):
    return c_dict[row['machine_type']]

if __name__ == '__main__':
    # 订单信息
    order_info = [
        ['A', '001', 3, 20],
        ['A', '002', 3, 50],
        ['B', '003', 4, 50],
        ['B', '004', 4, 20],
        ['B', '005', 4, 30],
        ['A', '006', 3, 50],
        ['B', '007', 4, 50],
        ['B', '008', 4, 50],
        ['A', '009', 3, 40],
        ['B', '010', 4, 50],
    ]
    order_num = len(order_info)
    transform_cost = [
        {'name': 'A-A', 'cost': 1},
        {'name': 'B-B', 'cost': 1},
        {'name': 'A-B', 'cost': 3},
        {'name': 'B-A', 'cost': 2},
    ]
    # 颜色信息
    c_dict = {'A': '#3475D0', 'B': '#E69646'}
    # 遗传算法规划问题
    epoch = 0
    ga_tsp = GA_TSP(func=cal_fitness, n_dim=order_num, size_pop=100, max_iter=500, prob_mut=1)
    best_order_sequence, best_fitness = ga_tsp.run()
    print(best_order_sequence, best_fitness)
    best_order_sequence_list = cal_order_sequence(best_order_sequence.tolist(), order_info, transform_cost)
    print(best_order_sequence_list)

    # 适应度画图
    fig, ax = plt.subplots(1, figsize=(10, 4))
    ax.plot(ga_tsp.generation_best_Y)
    plt.show()

    # 下面是测试
    # order_sequence_list = [0, 5, 6, 3, 4, 2, 7, 9, 1, 8]
    # order_sequence_list_info = cal_order_sequence(order_sequence_list,order_info,transform_cost)
    # print(order_sequence_list_info)
    # pass
